package niu.toy.spring.mvc;

import cn.hutool.core.lang.Assert;
import lombok.Data;
import niu.toy.spring.ioc.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * 封装Action方法
 */
@Data
public class HandlerMethod {
    private static final Logger logger = LoggerFactory.getLogger(HandlerMethod.class);

    private final Object bean;

    private final Class<?> beanType;

    private final Method method;


    private final HandlerMethodParameter[] parameters;

    public HandlerMethodParameter[] getMethodParameters() {
        return this.parameters;
    }

    public HandlerMethod(Object bean, Method method) {
        Assert.notNull(bean, "Bean is required");
        Assert.notNull(method, "Method is required");
        this.bean = bean;

        this.beanType = bean.getClass();
        this.method = method;
        this.parameters = initMethodParameters();
    }
    protected HandlerMethod(HandlerMethod handlerMethod) {
        Assert.notNull(handlerMethod, "HandlerMethod is required");
        this.bean = handlerMethod.bean;
        this.beanType = handlerMethod.beanType;
        this.method = handlerMethod.method;

        this.parameters = handlerMethod.parameters;
    }
    private HandlerMethodParameter[] initMethodParameters() {
        int count = this.method.getParameterCount();
        Parameter[] parameters=this.method.getParameters();
        HandlerMethodParameter[] result = new HandlerMethodParameter[count];
        for (int i = 0; i < count; i++) {
            HandlerMethodParameter parameter = new HandlerMethodParameter(this.method,i);
            parameter.setParameter(parameters[i]);
            result[i] = parameter;
        }
        return result;
    }


    /**
     * 把返回类型包装成方法参数类型
     */
    public HandlerMethodParameter getReturnValueType(@Nullable Object returnValue) {
        return new ReturnValueHandlerMethodParameter(returnValue);
    }

    private class ReturnValueHandlerMethodParameter extends HandlerMethodParameter {

        @Nullable
        private final Object returnValue;

        public ReturnValueHandlerMethodParameter(@Nullable Object returnValue) {
            super(HandlerMethod.this.getMethod(),-1);
            this.returnValue = returnValue;
        }

        protected ReturnValueHandlerMethodParameter(ReturnValueHandlerMethodParameter original) {
            super(original);
            this.returnValue = original.returnValue;
        }

        @Override
        public Class<?> getParameterType() {
            return (this.returnValue != null ? this.returnValue.getClass() :null);
        }

        @Override
        public ReturnValueHandlerMethodParameter clone() {
            return new ReturnValueHandlerMethodParameter(this);
        }
    }
}
